package com.wei.czz.framework.blog.controller;

import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.wei.czz.common.annotation.Auth;
import com.wei.czz.common.annotation.AuthLogin;
import com.wei.czz.common.annotation.Resubmit;
import com.wei.czz.common.dto.blog.*;
import com.wei.czz.common.enums.blog.BlogEnum;
import com.wei.czz.common.jsr303.group.OrderSearch;
import com.wei.czz.common.jsr303.group.Save;
import com.wei.czz.common.jsr303.group.Update;
import com.wei.czz.common.property.BatchProperty;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.Result;
import com.wei.czz.common.vo.blog.*;
import com.wei.czz.common.vo.blog.BlogFormVo;
import com.wei.czz.framework.blog.manager.BlogManager;
import com.wei.czz.framework.blog.service.BlogService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2025-01-23 09:51
 * className: BlogController 博客基本信息操作请求接口类
 * version: 2.0
 * description:
 */
@RestController
@RequestMapping("/blog")
@AllArgsConstructor
public class BlogController {

    private static final Logger log = LoggerFactory.getLogger(BlogController.class);

    private final BatchProperty batchProperty;

    private final BlogService blogService;

    private final BlogManager blogManager;

    /**
     * 保存博客接口
     * 保存博客信息，将该博客作为草稿，等待下一步操作
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-博客添加页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param blogVo 博客信息对象
     * @return 结果
     */
    @Resubmit(spEL = "'saveBlog' + #userId", message = "保存博客")
    @PostMapping("/save")
    @AuthLogin
    public Result<String> saveBlog(@Validated(Save.class) @RequestBody BlogVo blogVo) {
        log.info("开始保存用户博客业务。{}", blogVo);

        if (blogVo.getTagList().size() > BlogEnum.TAG_MAX_SIZE.getValue()) {
            log.info("博客关联标签数量超限");
            return Result.paramFail();
        }

        String id = blogManager.saveBlog(blogVo);

        log.info("保存用户博客业务结束");
        return Result.success(id);
    }

    /**
     * 博客提交审核接口
     * 调用方：
     *  1、浏览器-后台管理页面-博客添加页面调用
     * 此接口会校验是否重复提交
     * @param commitBlogVo 参数对象
     * @return 结果
     */
    @Resubmit(spEL = "'commitBlog' + #userId", message = "博客提交审核")
    @PostMapping("/commit")
    @AuthLogin
    public Result<Object> commitBlog(@Validated @RequestBody CommitBlogVo commitBlogVo) {
        log.info("开始博客提交审核业务。{}", commitBlogVo);

        blogManager.commitBlog(commitBlogVo);

        log.info("博客提交审核业务结束");
        return Result.success();
    }

    /**
     * 缓存博客接口
     * 根据博客主键列表，将对应的所有博客信息写入缓存中
     * <p>
     * 调用方
     *  1、浏览器-后台管理页-博客缓存管理页调用
     * <p>
     * 此接口会校验是否重复提交
     * @param idList 博客主键列表
     * @return 请求结果
     */
    @Resubmit(spEL = "'cacheBlog' + #userId", message = "缓存博客")
    @PostMapping("/cache")
    @Auth(permit = "cache:blog:opt")
    public Result<Object> cacheBlog(@RequestBody List<Long> idList) {
        log.info("开始缓存博客业务。idList={}", idList);

        if (idList == null || idList.isEmpty()) {
            log.info("缓存博客接口请求参数错误");
            return Result.paramFail();
        }
        if (batchProperty.getMaxSize() < idList.size()) {
            log.info("缓存博客数量超限");
            return Result.clientFail("一次缓存博客操作最多允许同时缓存" + batchProperty.getMaxSize() + "条博客");
        }

        blogManager.cacheBlog(idList);

        log.info("缓存博客信息业务结束");
        return Result.success();
    }

    /**
     * 缓存全部博客信息接口
     * 将系统所有博客信息写入缓存中
     * <p>
     * 调用方
     *  1、浏览器-后台管理页-博客缓存管理页调用
     * <p>
     * 此接口会校验是否重复提交
     * @return 请求结果
     */
    @Resubmit(message = "缓存全部博客")
    @GetMapping("/cache/all")
    @Auth(permit = "cache:blog:opt")
    public Result<Object> cacheAllBlog() {
        log.info("开始缓存全部博客信息业务");

        blogManager.cacheAllBlog();

        log.info("缓存全部博客信息业务结束");
        return Result.success();
    }

    /**
     * 获取用户自己的博客列表接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-我的博客管理页面调用
     * @param userBlogFormVo 用户博客检索Vo对象
     * @return 结果
     */
    @PostMapping("/self/page/list")
    @AuthLogin
    public Result<PageDto<UserBlogListDto>> getSelfBlogPageList(@Validated(OrderSearch.class) @RequestBody UserBlogFormVo userBlogFormVo) {
        log.info("开始用户获取自己的博客列表业务。{}", userBlogFormVo);

        PageDto<UserBlogListDto> pageDto = blogManager.getSelfBlogPageList(userBlogFormVo);

        log.info("用户获取自己的博客列表业务结束");
        return Result.success(pageDto);
    }

    /**
     * 获取我的博客管理页面枚举接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-我的博客管理页面调用
     * @return 结果
     */
    @GetMapping("/self/page/enum")
    @AuthLogin
    public Result<UserBlogPageEnumDto> getSelfBlogPageEnum() {
        log.info("开始获取我的博客管理页面枚举业务");

        UserBlogPageEnumDto userBlogPageEnumDto = blogManager.getSelfBlogPageEnum();

        log.info("获取我的博客管理页面枚举业务结束");
        return Result.success(userBlogPageEnumDto);
    }

    /**
     * 获取用户自己的已发布博客列表接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-我的博客管理页面调用
     * @param userBlogFormVo 参数对象
     * @return 结果
     */
    @PostMapping("/self/issue/page/list")
    @AuthLogin
    public Result<PageDto<UserIssueBlogListDto>> getSelfIssueBlogPageList(@Validated(OrderSearch.class) @RequestBody UserBlogFormVo userBlogFormVo) {
        log.info("开始用户获取自己的已发布博客列表业务。{}", userBlogFormVo);

        PageDto<UserIssueBlogListDto> pageDto = blogManager.getSelfIssueBlogPageList(userBlogFormVo);

        log.info("用户获取自己的已发布博客列表业务结束");
        return Result.success(pageDto);
    }

    /**
     * 获取保存博客管理页面枚举接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-博客添加页面调用
     * @return 结果
     */
    @GetMapping("/save/page/enum")
    @AuthLogin
    public Result<SaveBlogPageEnumDto> getSaveBlogPageEnum() {
        log.info("开始获取保存博客管理页面枚举业务");

        SaveBlogPageEnumDto saveBlogPageEnumDto = blogManager.getSaveBlogPageEnum();

        log.info("获取保存博客管理页面枚举业务结束");
        return Result.success(saveBlogPageEnumDto);
    }

    /**
     * 分页获取博客接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-平台博客页面调用
     * @param blogManageFormVo 博客检索Vo对象
     */
    @PostMapping("/manage/page/list")
    @Auth(permit = "blog:manage:list")
    public Result<PageDto<BlogManageListDto>> getManageBlogPageList(@Validated(OrderSearch.class) @RequestBody BlogManageFormVo blogManageFormVo) {
        log.info("开始分页获取博客业务。{}", blogManageFormVo);

        PageDto<BlogManageListDto> page = blogManager.getManageBlogPageList(blogManageFormVo);

        log.info("分页获取博客业务结束");
        return Result.success(page);
    }

    /**
     * 获取博客管理页面枚举接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-平台博客页面调用
     * @return 结果
     */
    @GetMapping("/manage/page/enum")
    public Result<BlogManagePageEnumDto> getManageBlogPageEnum() {
        log.info("开始获取博客管理页面枚举业务");

        BlogManagePageEnumDto blogManagePageEnumDto = blogManager.getManageBlogPageEnum();

        log.info("获取博客管理页面枚举业务结束");
        return Result.success(blogManagePageEnumDto);
    }

    /**
     * 分页查询博客缓存列表接口
     * 根据博客检索表单对象，分页查询博客缓存信息列表
     *
     * 调用方
     *  1、浏览器-后台管理页-博客缓存管理页调用
     * @param blogFormVo 博客查询请求参数对象
     * @return 请求结果
     */
    @PostMapping("/cache/list")
    @Auth(permit = "cache:blog:list")
    public Result<Map<String, Object>> getCacheBlogList(@RequestBody BlogFormVo blogFormVo) {
        log.info("开始分页查询博客缓存列表业务。{}", blogFormVo);

        if (blogFormVo.getCacheStatus() == null) {
            log.info("分页查询博客缓存列表接口请求参数错误");
            return Result.paramFail();
        }
        if (blogFormVo.getPage() == null || blogFormVo.getLimit() == null || StringUtils.isBlank(blogFormVo.getField())
            || StringUtils.isBlank(blogFormVo.getOrder())) {
            log.info("分页查询博客缓存列表接口分页参数错误");
            return Result.pageFail();
        }

        Map<String, Object> result = blogService.getCacheBlogList(blogFormVo);


        log.info("分页查询博客缓存列表业务结束");
        return Result.success(result);
    }

    /**
     * 获取博客修改数据接口
     * <p>
     * 调用方
     *  1、浏览器-后台管理页面-博客添加页面调用
     *  2、浏览器-后台管理页面-博客修改页面调用
     * @param id 主键
     * @return 结果
     */
    @GetMapping("/get/update")
    @AuthLogin
    public Result<BlogUpdateDto> getBlogUpdate(@RequestParam("id") Long id){
        log.info("开始获取博客更新信息业务。{}", id);

        BlogUpdateDto blogUpdateDto = blogManager.getBlogUpdate(id);

        log.info("获取博客更新信息业务结束");
        return Result.success(blogUpdateDto);
    }

    /**
     * 获取博客缓存信息接口
     * 根据博客id，获取博客缓存信息
     *
     * 调用方
     *  1、浏览器-后台管理页-博客缓存管理页调用
     * @param blogVo 博客请求参数对象
     * @return 请求结果
     */
    @PostMapping("/cache/info")
    @Auth(permit = "cache:blog:info")
    public Result<Map<String, Object>> getBlogOnCache(@RequestBody BlogVo blogVo) {
        log.info("开始获取博客缓存信息业务。{}", blogVo);

        if (Objects.isNull(blogVo.getId())) {
            log.info("获取博客缓存信息接口请求参数错误");
            return Result.paramFail();
        }

        Map<String, Object> result = blogManager.getBlogOnCache(blogVo.getId());

        log.info("获取博客缓存信息业务结束");
        return Result.success(result);
    }

    /**
     * 博客撤销审核接口
     * 用户撤回正在审核的博客，并将博客放回草稿列表中
     * <p>
     * 调用方：
     *  1、后台管理页面-我的博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     * @return 结果
     */
    @Resubmit(spEL = "'withdrawAudit' + #userId", message = "博客撤销审核")
    @PutMapping("/withdraw/audit")
    @AuthLogin
    public Result<Object> withdrawAudit(@RequestParam("id") Long id) {
        log.info("开始用户取消博客审核业务。id={}", id);

        blogManager.withdrawAudit(id);

        log.info("用户取消博客审核业务结束");
        return Result.success();
    }

    /**
     * 博客撤销编辑审核接口
     * 用户撤回正在编辑审核的博客，并将博客状态回滚成提交审核前的状态
     * <p>
     * 调用方：
     *  1、后台管理页面-我的博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     * @return 结果
     */
    @Resubmit(spEL = "'withdrawEditAudit' + #userId", message = "博客撤销编辑审核")
    @PutMapping("/withdraw/edit/audit")
    @AuthLogin
    public Result<Object> withdrawEditAudit(@RequestParam("id") Long id) {
        log.info("开始用户取消博客编辑审核业务。id={}", id);

        blogManager.withdrawEditAudit(id);

        log.info("用户取消博客编辑审核业务结束");
        return Result.success();
    }

    /**
     * 博客撤销申诉审核接口
     * 用户撤回正在申诉审核的博客，并将博客状态回滚成申诉前的状态
     * <p>
     * 调用方：
     *  1、后台管理页面-我的博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     * @return 结果
     */
    @Resubmit(spEL = "'withdrawAppealAudit' + #userId", message = "博客撤销申诉审核")
    @PutMapping("/withdraw/appeal/audit")
    @AuthLogin
    public Result<Object> withdrawAppealAudit(@RequestParam("id") Long id) {
        log.info("开始用户取消博客申诉审核业务。id={}", id);

        blogManager.withdrawAppealAudit(id);

        log.info("用户取消博客申诉审核业务结束");
        return Result.success();
    }

    /**
     * 修改博客接口
     * 注意：
     *  1、在‘修改博客页面’执行修改操作，根据博客当前的状态，做出以下几种处理。
     *    1.1、博客状态为‘审核’，对旧的博客内容修改，博客继续保持‘审核’状态。
     *    1.2、博客状态为‘发布’，对旧的博客内容修改，并将博客状态变为‘审核’状态，增加博客流程信息，删除博客发布记录。
     *    1.3、博客状态为‘下架’，对旧的博客内容修改，并将博客状态变为‘审核’状态，增加博客流程信息。
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-修改博客页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param blogVo 博客信息对象
     * @return 结果
     */
    @Resubmit(spEL = "'updateBlog' + #userId", message = "修改博客")
    @PostMapping("/update")
    @Auth(permit = "blog:edit")
    public Result<Object> updateBlog(@Validated(Update.class) @RequestBody BlogVo blogVo){
        log.info("开始修改博客业务。blogVo={}", blogVo);

        if (blogVo.getTagList().size() > BlogEnum.TAG_MAX_SIZE.getValue()) {
            log.info("用户修改博客内容接口，博客关联标签值参数错误");
            return Result.paramFail();
        }

        blogManager.updateBlog(blogVo);

        log.info("修改博客业务结束");
        return Result.success();
    }

    /**
     * 修改博客版权或者评论状态接口
     * <p>
     * 调用方：
     *  1、后台管理页面-我的博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id     博客主键
     * @param status 最新的状态
     * @param bool   修改的字段[true-评论 false-版权]
     * @return 结果
     */
    @Resubmit(spEL = "'updateBlogFieldStatus' + #userId", message = "修改博客状态")
    @PutMapping("/field/update")
    @Auth(permit = "blog:edit")
    public Result<Object> updateBlogFieldStatus(@RequestParam("id") Long id,
                                                @RequestParam("status") Integer status,
                                                @RequestParam("bool") Boolean bool) {
        log.info("开始修改博客版权或者评论状态业务。id={} status={} bool={}", id, status, bool);

        blogManager.updateBlogFieldStatus(id, status, bool);

        log.info("修改博客版权或者评论状态业务结束");
        return Result.success();
    }

    /**
     * 用户发布博客接口
     * <p>
     * 调用方：
     *  1、后台管理页面-我的博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     * @return 结果
     */
    @Resubmit(spEL = "'issueBlog' + #userId", message = "发布博客")
    @PutMapping("/issue")
    @AuthLogin
    public Result<Object> issueBlog(@RequestParam("id") Long id) {
        log.info("开始发布博客业务。id={}", id);

        blogManager.issueBlog(id);

        log.info("发布博客业务结束");
        return Result.success();
    }

    /**
     * 隐藏博客接口
     * <p>
     * 调用方：
     *  1、后台管理页面-我的博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     * @return 结果
     */
    @Resubmit(spEL = "'hideBlog' + #userId", message = "隐藏博客")
    @PutMapping("/hide")
    @AuthLogin
    public Result<Object> hideBlog(@RequestParam("id") Long id) {
        log.info("开始隐藏博客业务。id={}", id);

        blogManager.hideBlog(id);

        log.info("隐藏博客业务结束");
        return Result.success();
    }

    /**
     * 推荐博客接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     */
    @Resubmit(spEL = "'recommendBlog' + #userId", message = "推荐博客")
    @PutMapping("/recommend")
    @Auth(permit = "blog:recommend")
    public Result<Object> recommendBlog(@RequestParam("id") Long id) {
        log.info("开始推荐博客业务。id={}", id);

        blogManager.recommendBlog(id);

        log.info("推荐博客业务结束");
        return Result.success();
    }

    /**
     * 取消博客推荐接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     */
    @Resubmit(spEL = "'cancelRecommendBlog' + #userId", message = "取消推荐博客")
    @PutMapping("/cancel/recommend")
    @Auth(permit = "blog:recommend")
    public Result<Object> cancelRecommendBlog(@RequestParam("id") Long id) {
        log.info("开始取消推荐博客业务。id={}", id);

        blogManager.cancelRecommendBlog(id);

        log.info("取消推荐博客业务结束");
        return Result.success();
    }

    /**
     * 下架已经发布的博客接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param outBlogVo 参数对象
     */
    @Resubmit(spEL = "'outBlog' + #userId", message = "下架博客")
    @PostMapping("/out")
    @Auth(permit = "blog:out")
    public Result<Object> outBlog(@Validated @RequestBody OutBlogVo outBlogVo) {
        log.info("开始下架已经发布的博客业务。{}", outBlogVo);

        blogManager.outBlog(outBlogVo);

        log.info("下架已经发布的博客业务结束");
        return Result.success();
    }

    /**
     * 重新上架博客接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param id 博客主键
     */
    @Resubmit(spEL = "'putBlog' + #userId", message = "重新上架博客")
    @PutMapping("/put/blog")
    @Auth(permit = "blog:put")
    public Result<Object> putBlog(@RequestParam("id") Long id) {
        log.info("开始重新上架博客业务。id={}", id);

        blogManager.putBlog(id);

        log.info("重新上架博客业务结束");
        return Result.success();
    }

    /**
     * 删除博客接口
     * <p>
     * 调用方：
     *  1、浏览器-后台管理页面-我的博客管理页面调用
     * <p>
     * 此接口会校验是否重复提交
     * @param idList 博客主键列表
     */
    @Resubmit(message = "删除博客信息")
    @PostMapping("/delete")
    @AuthLogin
    public Result<Object> deleteBlog(@RequestBody List<Long> idList){
        log.info("开始删除博客业务。idList={}", idList);

        blogManager.deleteBlog(idList);

        log.info("删除博客业务结束");
        return Result.success();
    }

    /**
     * 删除博客缓存接口
     * 根据博客id列表，批量删除博客缓存信息
     * <p>
     * 调用方
     *  1、浏览器-后台管理页-博客缓存管理页调用
     * <p>
     * 此接口会校验是否重复提交
     * @param idList 博客主键列表
     * @return 请求结果
     */
    @Resubmit(spEL = "'deleteBlogCache' + #userId", message = "删除博客缓存")
    @DeleteMapping("/cache/delete")
    @Auth(permit = "cache:blog:delete")
    public Result<Object> deleteBlogCache(@RequestBody List<String> idList) {
        log.info("开始删除博客缓存业务。idList={}", idList);

        if (CollectionUtils.isEmpty(idList)) {
            log.info("博客主键列表为空");
            return Result.clientFail("博客主键不能为空");
        }
        if (batchProperty.getMaxSize() < idList.size()) {
            log.info("删除博客缓存数量超限");
            return Result.clientFail("一次删除博客缓存操作最多允许同时删除" + batchProperty.getMaxSize() + "个缓存");
        }

        blogManager.deleteBlogCache(idList);

        log.info("删除博客缓存业务结束");
        return Result.success();
    }

    /**
     * 清空博客缓存接口
     * <p>
     * 调用方
     *  1、浏览器-后台管理页-博客缓存管理页调用
     * <p>
     * 此接口会校验是否重复提交
     * @return 请求结果
     */
    @Resubmit(spEL = "'clearBlogCache' + #userId", message = "清空博客缓存")
    @DeleteMapping("/cache/clear")
    @Auth(permit = "cache:blog:delete")
    public Result<Object> clearBlogCache() {
        log.info("开始清空博客缓存业务");

        blogManager.clearBlogCache();

        log.info("清空博客缓存业务结束");
        return Result.success();
    }

}
